﻿#include "CentralCache.h"
#include "PageCache.h"


CentralCache CentralCache::_instance;

// 从SpanList里面获取⼀个⾮空的span 
Span* CentralCache::GetOneSpan(SpanList& list, size_t byte_size)                                 
{
	Span* it = list.Begin();
	while (it != list.End())
	{
		if (it->_freeList == nullptr)
		{
			it = it->_next;
		}
		else
		{
			return it;
		}
	}

	// 走到这里centralCache桶里面的操作已经结束，为了防止其他线程释放桶时阻塞等待，在这里将桶解锁。
	list.UnLock();

	// 走到这里说明centralCache中没有非空的span，于是现在要向pageCache中申请新的span
	PageCache::GetInstance()->Lock();
	assert(byte_size > 0);
	size_t k = SizeClass::NumMovePage(byte_size);
	assert(k > 0);
	Span* newSpan = PageCache::GetInstance()->NewSpan(k);
	PageCache::GetInstance()->UnLock();

	// 申请得到的Span需要切分成小块内存，然后插入到_freeList中
	// 此时我们要将newSpan的第一个插入到_freeList中，所以需要知道newSpan的地址
	char* start = (char*)(newSpan->_pageId << PAGE_SHIFT);
	size_t bytesSize = newSpan->_n << PAGE_SHIFT;
	char* end = start + bytesSize;

	newSpan->_freeList = start;
	start += byte_size;
	void* tail = newSpan->_freeList;
	while (start < end)
	{
		NextObj(tail) = start;
		tail = NextObj(tail); 
		start += byte_size;
	}
	list.PushFront(newSpan);

	// 此时得到了sapn，此函数返回后会跳到centralCache的FetchRangeObj函数中，需要继续访问centralCache的桶，于是加锁
	list.Lock();


	return newSpan;
}


// 从中⼼缓存获取⼀定数量的对象给thread cache 
size_t CentralCache::FetchRangeObj(void*& start, void*& end, size_t batchNum, size_t size) 
{
	size_t index = SizeClass::Index(size);
	_spanList[index].Lock();

	Span* span = GetOneSpan(_spanList[index], size);
	assert(span);
	assert(span->_next); // 至少有一个

	start = span->_freeList;
	end = start;
	size_t i = 0;
	size_t actualNum = 1;
	while (i < batchNum - 1 && NextObj(end) != nullptr)
	{
		end = NextObj(end);
		i++;
		++actualNum;
	}
	span->_freeList = NextObj(end);

	NextObj(end) = nullptr;
	
	span->_useCount += actualNum;
	_spanList[index].UnLock();


	return actualNum;
}
// 将⼀定数量的对象释放到span跨度 
void CentralCache::ReleaseListToSpans(void* start, size_t byte_size)
{

}
